<script setup>
import { onMounted, ref, watch } from 'vue'
import Tile from './Tile.vue';
import { devMode, ColorList, TileNumberRange, clickLimit } from './config.js'
import Gameover from './Gameover.vue'
import Board from './Board.vue'
const currentPage = ref('Board')
let clickCount = 0
const clickCountdown = ref(clickLimit)
//TODO:需要加入每次刷新时的全局检测三消功能
const streak = ref(0)
let position = ref([])
const isNumberToggle = ref(true)
const isScoreAnimating = ref(false)
const score = ref(0)
const isProcessing = ref(false)
const match3IndexArray = ref([])
const boardDimension = ref(5)
const devMessages = ref([])
const columnedData = ref([])
const multiply = ref(1)
const isMultiplyAnimating = ref(false)
const emit = defineEmits(['gameover'])
let maxStreak = 0
let maxMultiply = 1
const tileAnimationTime = 1000

//当score变化的时候播放动画
watch(score, () => {
  isScoreAnimating.value = true
  setTimeout(() => {
    isScoreAnimating.value = false
  }, 1010)
})

//监听游戏结束
watch(clickCountdown, (newVal, oldVal) => {

  if (newVal < 1) {

    emit('gameover', score.value, maxStreak, maxMultiply, clickCount)
    restartGame()
    clickCountdown.value = clickLimit
  }
}
)
// 添加一个新的响应式变量来控制倍数动画

// 监听倍数变化
watch(multiply, (newVal, oldVal) => {
  if (newVal > oldVal && newVal > 1) {
    isMultiplyAnimating.value = true
    setTimeout(() => {
      isMultiplyAnimating.value = false
    }, 1000)
  }
})
const generateOneTile = () => ({ color: Math.floor(Math.random() * ColorList.length), number: Math.floor(Math.random() * ColorList.length) })

const generateNewBoardData = () =>
  Array.from({ length: boardDimension.value * boardDimension.value }, () => (generateOneTile()))


const flatBoardData = ref(generateNewBoardData())


const restartGame = () => {
  flatBoardData.value = generateNewBoardData()
  score.value = 0
  streak.value = 0
  multiply.value = 1

  //点击刷新棋盘之后执行的函数
}

const flatToColumnedData = (a) => {
  let ColumnedData = Array.from({ length: boardDimension.value }, () => [])
  a.forEach((item, index) => {
    ColumnedData[index % boardDimension.value].push({ ...item, index: index })
  })
  return ColumnedData
}


watch(flatBoardData.value, () => {
  columnedData.value = flatToColumnedData(flatBoardData.value)
})
//
const flatToRowedData = (a) => Array.from({ length: boardDimension.value }, (_, index) => a.slice(index * boardDimension.value, (index + 1) * boardDimension.value))


const columnToFlatData = (a) => flatToColumnedData(a.flat())
/**
 * 显示相同行/列的元素
 * @param index 点击的方块在flatBoardData中的索引
 * @returns 包含行和列的对象数据
 */
const showPeers = (index) => {
  const rowNumber = Math.floor(index / boardDimension.value)
  const columnNumber = index % boardDimension.value + 1

  const columnPeers = flatBoardData.value.filter((item, index) =>
    index % boardDimension.value === columnNumber - 1
  )

  const rowPeers = flatBoardData.value.slice(rowNumber * boardDimension.value, rowNumber * boardDimension.value + boardDimension.value)

  return { row: rowPeers, column: columnPeers }
}

const wholeBoardScan = () => {
}

/**  检测连续的数字
*@param {Array} a 需要检测的单个数组
*@returns {Array}包含符合要求的元素索引
 */
function matchNumberCheck(a, n) {

  // 提取出原数组中的数字信息,把连续数字检测转化为相同数字检测
  a = a.map((item, index) => item.number - index)
  return matchNCheckMini(a, n)

}
/**
 * 
 * @param a 需要检测的数组
 * @param n 检测连续n个元素
 * @returns {Array}返回满足条件的元素索引
 */
const matchNColorCheck = (a, n) => {
  // 提取出原数组中的颜色信息
  a = a.map(item => item.color)
  //输出的数组中保存的是连续的元素的索引
  return matchNCheckMini(a, n)
}
const matchNCheckMini = function (a, n) {
  let theSameElementIndex = []
  let i = 0;
  while (i < a.length - (n - 1)) {

    let j = i + 1;
    theSameElementIndex = [i]
    while (a[i] === a[j]) {

      theSameElementIndex.push(j)
      j++;//最前的索引指针进一
    }
    i = j//防止重复判定
  }
  return theSameElementIndex.length > (n - 1) ? theSameElementIndex : []

}
//TODO:重新生成数据,需要实现下落效果
const refillData = () => {
  //首先在以列组织的数组里找出满足满足消除条件的元素索引



  match3IndexArray.value.forEach((item) => {
    console.log('set-timeout done')
    flatBoardData.value[item] = generateOneTile()
  })

  match3IndexArray.value = []

}
/**
 * 点击方块之后的逻辑封装,包含子函数
 * @param tile 点击的方块对象
 * @param index 点击方块在flatBoardData中的索引
 * @function updateTile 点击方块之后,刷新显示方块的逻辑
 * @function matchCheck 点击方块之后,检测三消
 * 
 */
function handleTileClick(tile, index) {
  clickCountdown.value--
  clickCount++
  updateTile(tile, index)

  matchCheck(index)

}
/**
 * 点击方块之后,刷新显示方块的逻辑
 * @param tile 点击的方块对象
 * @param index 点击方块在flatBoardData中的索引
 */
const updateTile = (tile, index) => {

  flatBoardData.value[index].color = (tile.color + 1) % ColorList.length

  flatBoardData.value[index].number = (tile.number + 1) % TileNumberRange
}

/**
 * 检测三消的大函数,封装了许多小的逻辑
 * @param index 点击的方块在flatBoardData中的索引
 * @function refillData 三消之后,重新装填数据
 */
function matchCheck(index) {


  //三消的逻辑
  if (reportTileMatch3Index(index, matchNColorCheck).length > 2 || reportTileMatch3Index(index, matchNumberCheck).length > 2) {
    //刷新点击计数器
    clickCountdown.value = clickLimit
    //连击数增加
    streak.value++
    //最大连击数更新逻辑
    maxStreak < streak.value ? maxStreak = streak.value : null
    //把三消的元素坐标写入全局变量,为之后的refillData做准备,也为watch侦听器做准备
    match3IndexArray.value = [...reportTileMatch3Index(index, matchNColorCheck), ...reportTileMatch3Index(index, matchNumberCheck)]
    //分数加分

    //如果颜色和数字两个条件都满足,则加大分
    if (reportTileMatch3Index(index, matchNColorCheck).length > 2 && reportTileMatch3Index(index, matchNumberCheck).length > 2) {
      multiply.value = 10
    }
    //倍数的逻辑
    multiply.value = match3IndexArray.value.length - 2 + streak.value - 1

    maxMultiply < multiply.value ? maxMultiply = multiply.value : null

    score.value += 10 * match3IndexArray.value.length * multiply.value
    //dev信息显示
    devMessages.value = reportTileMatch3Index(index, matchNColorCheck)
    //等待1s的动画结束之后刷新棋盘
    setTimeout(() => {
      // 刷新棋盘
      refillData();
      //开放点击
      isProcessing.value = false
    }, 1050)
  } else {
    multiply.value = 1
    streak.value = 0
  }
}


const showPosition = (index) => {
  const rowNumber = Math.floor(index / boardDimension.value) + 1
  const columnNumber = index % boardDimension.value + 1

  position.value = [rowNumber, columnNumber]
}



//上报要消除 的元素index,注意函数的第二个参数是另一个检测函数
/**
 * 
 * @param index 点击的方块在flatBoardData中的索引
 * @param checkFunction 检测函数
 * @returns {Array}去重之后满足消除规则的所有元素在flatBoardData中的索引
 *
 */
const reportTileMatch3Index = (index, checkFunction) => {
  const rowNumber = Math.floor(index / boardDimension.value)
  const columnNumber = index % boardDimension.value


  const column = showPeers(index).column
  const row = showPeers(index).row

  const matchedColumnID = checkFunction(column, 3).map((item) => columnNumber + item * boardDimension.value)


  const matchedRowID = checkFunction(row, 3).map((item) => rowNumber * boardDimension.value + item)

  return makeUnique(...matchedColumnID, ...matchedRowID)
}
/**
 * 去重函数:主要使用了数组展开的语法和set来去重
 * @param a 需要去重的数组
 * @returns {Array}去重之后的数组 
 */
function makeUnique(...a) {
  return [...new Set(a)]
}
</script>

<template>

  <div class="window">
    <div class="info-bar">

      <div class="introduction">
        <h3>说明:</h3>
        <p>在一行或者一列中,如果有相同颜色的方块,或者连续递增的数字,则可以消除方块,获得加分。</p>
      </div>
      <button id='replay' @click="restartGame()">🥵</button>
    </div>

    <div class="board"
      :style="{ gridTemplateColumns: `repeat(${boardDimension},1fr)`, gridTemplateRows: `repeat(${boardDimension},1fr)` }">
      <Tile :style="{ pointerEvents: match3IndexArray.includes(index) ? 'none' : 'auto' }"
        :class="{ 'matched-tile': match3IndexArray.includes(index) }" v-for="(tile, index) in flatBoardData"
        :showNumber=isNumberToggle :colorPointer="tile.color" :tileNumber="tile.number"
        @click="handleTileClick(tile, index)" :index="index" :key="index"></Tile>
    </div>

    <div class="status-bar">
      <div class="counter">
        <div v-for="i in clickCountdown">⭕️</div>
      </div>
      <!-- <div class="counter">剩余点击次数:{{ clickCountdown }}</div> -->

      <div class="score" :class="{ animate: isScoreAnimating }">
        分数:{{ score }}</div>

      <div class="multiply" :class="{ animate: isMultiplyAnimating }">倍数:{{ multiply }}倍!
      </div>

      <transition name="streak-fade" mode="out-in">
        <div class="streak" v-if="streak > 1">{{ streak }}连击!</div>
      </transition>
    </div>

    <!-- 不显示 -->
    <div class="tool-bar">
      <button @click="restartGame()" :disabled="true">刷新棋盘</button>
      <button @click="isNumberToggle = !isNumberToggle">隐藏/显示数字</button>
    </div>

    <!-- 不显示 -->
    <div class="dev-bar">
      <p>{{ columnedData }}</p>
      <p>{{ devMessages }}</p>
    </div>
  </div>


</template>

<style scoped>
:root {
  --tileAnimationTime: 0.5s;
}

.matched-tile {
  animation: tileMatchedAnimation 1s ease-in-out forwards;
}

@keyframes tileMatchedAnimation {
  0% {
    transform: scale(1);
  }

  50% {
    transform: scale(1.3);
  }

  100% {
    transform: scale(1);
  }
}

.board {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  grid-template-rows: repeat(5, 1fr);
  justify-content: center;
  justify-items: center;
  gap: 1vw;
  /* width: 70%; */
  margin: 2vh;
  align-items: center;
}

.tool-bar {

  display: none;
  padding: 10px;
  border: 2px solid gray;
  margin: 10px;

}

.info-bar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 10px;
  border: 2px solid rgb(197, 75, 75);
  margin: 10px;
}

.dev-bar {
  display: none;
  padding: 10px;
  border: 2px solid gray;
  margin: 10px;
}


.status-bar {
  font-weight: 700;
  font-size: 2rem;
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  /* padding: 10px; */
  border: 10px solid rgb(186, 117, 117);
  border-radius: 15px;
  margin: 10px;
  gap: 0px;
}

button {
  margin-left: 10px;
}

.score {
  color: rgb(240, 105, 31);
}

.score.animate {
  animation: scorePulse 1s ease-in-out forwards;
}

.multiply.animate {
  animation: gradientFlow 1s ease-in-out forwards;
}

.multiply {
  color: #ceb898;
  /* 添加渐变背景以便动画使用 */
  background: linear-gradient(90deg, #cf878a, #4265e6, #a1c4fd, #e7965f);
  background-size: 300% 300%;
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
}

.streak {
  position: absolute;
  bottom: 150px;
  color: rgb(230, 128, 119);
  font-style: italic;
}

@keyframes scorePulse {
  0% {
    transform: scale(1);
    color: orange;
  }

  50% {
    transform: scale(1.3);
    color: wheat;
  }

  100% {
    transform: scale(1);
    color: orange;
  }
}

.window {
  background-color: #ebf9b1;
  height: 100dvh;
  width: 100dvw;
  display: flex;
  flex-direction: column;
}

@keyframes gradientFlow {
  0% {
    background-position: 0% 50%;
  }

  50% {
    background-position: 100% 50%;
  }

  100% {
    background-position: 0% 50%;
  }
}

/* 连击文字的过渡动画 */
.streak-fade-enter-active {
  animation: streakEnter 0.5s ease-out forwards;
}

.streak-fade-leave-active {
  animation: streakLeave 0.5s ease-in forwards;
}

@keyframes streakEnter {
  0% {
    opacity: 0;
    transform: scale(0.5) translateY(20px);
  }

  100% {
    opacity: 1;
    transform: scale(1) translateY(0);
  }
}

@keyframes streakLeave {
  0% {
    opacity: 1;
    transform: scale(1) translateY(0);
  }

  100% {
    opacity: 0;
    transform: scale(0.5) translateY(-20px);
  }
}

.counter {
  font-size: 1.5rem;
  font-weight: 700;
  color: orange;
  display: flex;
  flex-direction: row;
}
</style>